home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / os2 / gnuwget.zip / wget-1.4.3 / src / retr.c < prev    next >
C/C++ Source or Header  |  1997-02-09  |  14KB  |  554 lines

  1. /* File retrieval.
  2.    Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
  3.    
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2 of the License, or
  7.    (at your option) any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.    
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18.  
  19. #ifdef HAVE_CONFIG_H
  20. #  include <config.h>
  21. #endif /* HAVE_CONFIG_H */
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #ifdef HAVE_UNISTD_H
  28. #  include <unistd.h>
  29. #endif /* HAVE_UNISTD_H */
  30. #include <errno.h>
  31. #ifdef HAVE_STRING_H
  32. #  include <string.h>
  33. #else
  34. #  include <strings.h>
  35. #endif /* HAVE_STRING_H */
  36. #include <ctype.h>
  37. #include <assert.h>
  38.  
  39. #include "wget.h"
  40. #include "options.h"
  41. #include "utils.h"
  42. #include "retr.h"
  43. #include "url.h"
  44. #include "recur.h"
  45. #include "ftp.h"
  46. #include "html.h"
  47. #include "http.h"
  48. #include "host.h"
  49. #include "connect.h"
  50.  
  51. /* global variables */
  52. extern struct options opt;
  53.  
  54. /* Buffered input variables: */
  55. char buffer[INPUT_BUFFER_SIZE]; /* The input buffer itself. */
  56. char *buffer_pos;               /* The current position in the buffer. */
  57. size_t buffer_left;             /* Number of bytes left in the buffer:
  58.                    buffer_left = buffer_pos - buffer */
  59.  
  60. /* Variables used for the timer.  */
  61. long internal_secs, internal_msecs;
  62.  
  63.  
  64. /* The function for reading from file descriptor fd, char-by-char. If
  65.    there is anything in the buffer, the character is returned from the
  66.    buffer. Otherwise, refill the buffer and return the first
  67.    character.
  68.  
  69.    The return value is the same as with read(2). On buffered read, the
  70.    function returns 1. */
  71. int
  72. buf_readchar(int fd, char *ret)
  73. {
  74.    int res;
  75.  
  76.    if (buffer_left)
  77.    {
  78.       --buffer_left;
  79.       *ret = *buffer_pos++;
  80.    }
  81.    else
  82.    {
  83.       buffer_pos = buffer;
  84.       buffer_left = 0;
  85.       res = iread(fd, buffer, INPUT_BUFFER_SIZE);
  86.       if (res <= 0)
  87.      return res;
  88.       buffer_left = res - 1;
  89.       *ret = *buffer_pos++;
  90.    }
  91.    return 1;
  92. }
  93.  
  94. /* This is similar to buf_readchar, only it doesn't move the buffer
  95.    position.  */
  96. int
  97. buf_peek(int fd, char *ret)
  98. {
  99.    int res;
  100.  
  101.    if (buffer_left)
  102.       *ret = *buffer_pos;
  103.    else
  104.    {
  105.       buffer_pos = buffer;
  106.       buffer_left = 0;
  107.       res = iread(fd, buffer, INPUT_BUFFER_SIZE);
  108.       if (res <= 0)
  109.      return res;
  110.       buffer_left = res;
  111.       *ret = *buffer_pos;
  112.    }
  113.    return 1;
  114. }
  115.  
  116. /* Flush the buffer. Its arguments are the pointer where to copy the
  117.    buffer contents and how much of the contents may be copied in a
  118.    chunk. The return value is the number of bytes actually copied. If
  119.    the buffer is empty, 0 is returned. */
  120. int
  121. buf_flush(char *where, int maxsize)
  122. {
  123.    int howmuch;
  124.    
  125.    if (!buffer_left)
  126.       return 0;
  127.    else
  128.    {
  129.       howmuch = buffer_left <= maxsize ? buffer_left : maxsize;
  130.       if (where)
  131.      memcpy(where, buffer_pos, howmuch);
  132.       buffer_left -= howmuch;
  133.       buffer_pos += howmuch;
  134.       return howmuch;
  135.    }
  136. }
  137.  
  138. /* Discard the contents of the input buffer. */
  139. void
  140. buf_discard(void)
  141. {
  142.    buffer_left = 0;
  143.    buffer_pos = buffer;
  144. }
  145.  
  146. /* Reads the contents of file descriptor fd, until it is closed, or a
  147.    read error occurs. The data is read in parts BUFFER_SIZE bytes
  148.    long, and stored to stream fp, which should have been open for
  149.    writing.
  150.  
  151.    If opt.verbose is set, the progress is also shown. Variable restval
  152.    is used to represent a value from which to start downloading (which
  153.    will be shown accordingly). If restval is set, the stream should
  154.    have been open for appending.
  155.  
  156.    The function exits and returns codes of 0, -1 and -2 if the
  157.    connection was closed, there was a read error, or if it could not
  158.    write to the output stream, respectively.
  159.  
  160.    IMPORTANT: The function flushes the contents of the buffer in
  161.    buf_flush() before actually reading from fd. If you wish to read
  162.    from fd immediately, flush or discard the buffer. */
  163. int
  164. get_contents(int fd, FILE *fp, long *len, long restval, int nobuf)
  165. {
  166.    int res;
  167.    static char c[BUFFER_SIZE];
  168.  
  169.    *len = restval;
  170.    /* Initialize show_progress. */
  171.    if (opt.verbose)
  172.       show_progress(restval, 1);
  173.    /* Flush the input buffer if !nobuf. */
  174.    if (!nobuf)
  175.    {
  176.       while ((res = buf_flush(c, BUFFER_SIZE)) != 0)
  177.       {
  178.      if (!fwrite(c, sizeof(char), res, fp))
  179.         return -2;
  180.      if (opt.verbose)
  181.      {
  182.         if (show_progress(res, 0))
  183.            fflush(fp);
  184.      }
  185.      *len += res;
  186.       }
  187.    }
  188.    /* Read from fd while there is available data. */
  189.    do
  190.    {
  191.       res = iread(fd, c, BUFFER_SIZE);
  192.       if (res > 0)
  193.       {
  194.      if (!fwrite(c, sizeof(char), res, fp))
  195.         return -2;
  196.      if (opt.verbose)
  197.      {
  198.         if (show_progress(res, 0))
  199.            fflush(fp);
  200.      }
  201.      *len += res;
  202.       }
  203.    } while (res > 0);
  204.    if (res < -1)
  205.       res = -1;
  206.    if (opt.verbose)
  207.       fprintf(opt.lfile, "\n\n");
  208.    return res;
  209. }
  210.  
  211. /* Show the dotted progress report of file loading. Called with length
  212.    and a flag to tell it whether to reset or not. It keeps the offset
  213.    information in static local variables.
  214.  
  215.    Return value: 1 or 0, designating whether any dots have been drawn.
  216.  
  217.    If the init argument is set, the routine will initialize.
  218.  
  219.    If the res is non-zero, res/line_bytes lines are skipped
  220.    (meaning the appropriate number ok kilobytes), and the number of
  221.    "dots" fitting on the first line are drawn as ','. */
  222. int
  223. show_progress(long res, int init)
  224. {
  225.    static long line_bytes;
  226.    static long offs;
  227.    static int ndot, nrow;
  228.    int any_output;
  229.  
  230.    any_output = 0;
  231.    /* init set means initialization. If res is set, it also means that
  232.       the retrieval is *not* done from the beginning. The part that
  233.       was already retrieved is not shown again. */
  234.    if (init == 1)
  235.    {
  236.       /* Generic initialization of static variables. */
  237.       offs = 0L;
  238.       ndot = nrow = 0;
  239.       line_bytes = (long)opt.dots_in_line * opt.dot_bytes;
  240.       if (res)
  241.       {
  242.      if (res >= line_bytes)
  243.      {
  244.         nrow = res / line_bytes;
  245.         res %= line_bytes;
  246.         fprintf(opt.lfile, "\n          [ skipping %dK ]",
  247.             (int)((nrow * line_bytes) / 1024));
  248.         ndot = 0;
  249.      }
  250.       }
  251.       fprintf(opt.lfile, "\n%5ldK ->", nrow * line_bytes / 1024);
  252.    }
  253.    /* Offset gets incremented by current value. */
  254.    offs += res;
  255.    /* While offset is >= opt.dot_bytes, print dots, taking care
  256.       that every 50th dot needs to be preceded by a status message. */
  257.    for (; offs >= opt.dot_bytes; offs -= opt.dot_bytes)
  258.    {
  259.       if (!(ndot % opt.dot_spacing))
  260.      fputc(' ', opt.lfile);
  261.       any_output = 1;
  262.       if (init)
  263.      fputc(',', opt.lfile);
  264.       else
  265.      fputc('.', opt.lfile);
  266.       ++ndot;
  267.       if (ndot == opt.dots_in_line)
  268.      ndot = 0;
  269.       if (ndot == 0)
  270.       {
  271.      ++nrow;
  272.      fprintf(opt.lfile, "\n%5ldK ->",
  273.          nrow * line_bytes / 1024);
  274.       }
  275.    }
  276.    return any_output;
  277. }
  278.  
  279. /* A function to reset the internal timer. */
  280. void
  281. reset_timer(void)
  282. {
  283. #ifdef HAVE_GETTIMEOFDAY
  284.    struct timeval t;
  285.    gettimeofday(&t, NULL);
  286.    internal_secs = t.tv_sec;
  287.    internal_msecs = t.tv_usec / 1000;
  288. #else
  289.    internal_secs = time(NULL);
  290.    internal_msecs = 0;
  291. #endif
  292. }
  293.  
  294. /* The time elapsed from the last call to reset_timer, in msecs. */
  295. long
  296. elapsed_time(void)
  297. {
  298. #ifdef HAVE_GETTIMEOFDAY
  299.    struct timeval t;
  300.    gettimeofday(&t, NULL);
  301.    return ((t.tv_sec - internal_secs) * 1000
  302.        + (t.tv_usec / 1000 - internal_msecs));
  303. #else
  304.    return (long)time(NULL) - internal_secs;
  305. #endif
  306. }
  307.  
  308. /* The function returns pointer to a static char[] buffer in which
  309.    zero-terminated string-representation of time (in form hh:mm:ss) is
  310.    printed. It is shamelessly non-reentrant, but who cares? :)
  311.  
  312.    If tm is non-NULL, it also returns the time_t of the current time.  */
  313. char *
  314. time_str(time_t *tm)
  315. {
  316.    static char tms[15];
  317.    struct tm *ptm;
  318.    time_t tim;
  319.  
  320.    *tms = '\0';
  321.    tim = time(tm);
  322.    if (tim == -1)
  323.       return tms;
  324.    ptm = localtime(&tim);
  325.    sprintf(tms, "%02d:%02d:%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
  326.    return tms;
  327. }
  328.  
  329. /* Print out the appropriate download rate.  Appropriate means that if
  330.    rate is > 1024 bytes per second, kilobytes are used, and if rate >
  331.    1024 * 1024 bps, megabytes are used. */
  332. char *
  333. rate(long bytes, long msecs)
  334. {
  335.    static char res[15];
  336.    double dlrate;
  337.  
  338.    if (!msecs)
  339.       ++msecs;
  340.    dlrate = (double)1000 * bytes / msecs;
  341.    if (dlrate < 1024.0)
  342.       sprintf(res, "%.2f B/s", dlrate);
  343.    else if (dlrate < 1024.0 * 1024.0)
  344.       sprintf(res, "%.2f KB/s", dlrate / 1024.0);
  345.    else
  346.       sprintf(res, "%.2f MB/s", dlrate / (1024.0 * 1024.0));
  347.    return res;
  348. }
  349.  
  350. /* Retrieve the given URL. Decides which loop to call -- HTTP, FTP, or
  351.    simply copy it with file://. */
  352. uerr_t
  353. retrieve_url(const char *origurl, char **file, char **newloc,
  354.          const char *refurl, int *dt)
  355. {
  356.    urlinfo *u;
  357.    uerr_t result;
  358.    char *url;
  359.    int local_use_proxy, location_changed, dummy, oldrec;
  360.    char *mynewloc, *proxy;
  361.  
  362.    /* If dt is NULL, just ignore it. */
  363.    if (!dt)
  364.       dt = &dummy;
  365.    url = nstrdup(origurl);
  366.    if (newloc)
  367.       *newloc = NULL;
  368.    if (file)
  369.       *file = NULL;
  370.    location_changed = 0;
  371.    
  372.    /* This ugly loop is because of Location headers. */
  373.    do
  374.    {
  375.       u = newurl();
  376.       /* Parse the URL.  If the new location was gained from the
  377.          Location header, we need "strict" parsing.  RFC2068 is clear
  378.          about `Location:' containing an absoluteURI.  */
  379.       result = parseurl(url, u, location_changed);
  380.       if (result != URLOK)
  381.       {
  382.      freeurl(u, 1);
  383.      if (!opt.quiet)
  384.         fprintf(opt.lfile, "%s: %s.\n", url, uerrmsg(result));
  385.      return result;
  386.       }
  387.  
  388.       /* Set the referer. */
  389.       if (refurl)
  390.      u->referer = nstrdup(refurl);
  391.       else
  392.      u->referer = NULL;
  393.       
  394.       local_use_proxy = USE_PROXY(u);
  395.       if (local_use_proxy)
  396.       {
  397.      urlinfo *pu;
  398.      
  399.      pu = newurl();
  400.      /* Copy the original URL to new location. */
  401.      memcpy(pu, u, sizeof(*u));
  402.      pu->proxy = NULL; /* A minor correction :) */
  403.      /* Initialize u to nil. */
  404.      memset(u, 0, sizeof(*u));
  405.      u->proxy = pu;
  406.      /* Get the appropriate proxy, according to protocol. */
  407.      proxy = getproxy(pu->proto);
  408.      if (!proxy)
  409.      {
  410.         if (!opt.quiet)
  411.            fprintf(opt.lfile, "Could not find proxy host.\n");
  412.         freeurl(u, 1);
  413.         return PROXERR;
  414.      }
  415.      /* Parse the proxy URL. */
  416.      result = parseurl(proxy, u, 0);
  417.      if (result != URLOK || u->proto != URLHTTP)
  418.      {
  419.         if (!opt.quiet)
  420.         {
  421.            if (u->proto == URLHTTP)
  422.           fprintf(opt.lfile, "Proxy %s: %s.\n", proxy,
  423.               uerrmsg(result));
  424.            else
  425.           fprintf(opt.lfile, "Proxy %s: Must be HTTP.\n", proxy);
  426.         }
  427.         freeurl(u, 1);
  428.         return PROXERR;
  429.      }
  430.      u->proto = URLHTTP;
  431.       } /* local_use_proxy */
  432.       
  433.       assert(u->proto != URLFILE); /* For now... */      
  434.       mynewloc = NULL;
  435.       
  436.       if (u->proto == URLHTTP)
  437.      result = http_loop(u, &mynewloc, dt);
  438.       else if (u->proto == URLFTP)
  439.       {
  440.      /* If the location has changed, we must not allow recursive
  441.         FTP retrieval, so we save recursion to oldrec, and restore
  442.         it later.  */
  443.      oldrec = opt.recursive;
  444.      if (location_changed)
  445.         opt.recursive = 0;
  446.      result = ftp_loop(u, dt);
  447.      if (location_changed)
  448.         opt.recursive = oldrec;
  449.      /* There is a possibility of having HTTP being redirected to
  450.         FTP.  In these cases we must decide whether the text is
  451.         HTML according to the suffix.  The HTML suffixes are
  452.         `.html' and (yuck!) `.htm', case-insensitive.  */
  453.      if (location_changed && u->local && (u->proto == URLFTP ))
  454.      {
  455.         char *suf = suffix(u->local);
  456.         if (suf && (!strcasecmp(suf, "html") || !strcasecmp(suf, "htm")))
  457.            *dt |= TEXTHTML;
  458.      }
  459.       }
  460.       location_changed = (result == NEWLOCATION);
  461.       if (location_changed)
  462.       {
  463.      /* Check for redirection to oneself. */
  464.      if (url_equal(url, mynewloc))
  465.      {
  466.         if (!opt.quiet)
  467.            fprintf(opt.lfile, "%s: Redirection to itself.\n", mynewloc);
  468.         return WRONGCODE;
  469.      }
  470.       }
  471.       if (mynewloc)
  472.       {
  473.      free(url);
  474.      url = mynewloc;
  475.       }
  476.       if (!location_changed && file)
  477.       {
  478.      if (u->local)
  479.         *file = nstrdup(u->local);
  480.      else
  481.         *file = NULL;
  482.       }
  483.       freeurl(u, 1);
  484.    } while (location_changed);
  485.  
  486.    if (newloc)
  487.       *newloc = url;
  488.    else
  489.       free(url);
  490.    
  491.    return result;
  492. }
  493.  
  494. /* Find the URL-s in the file and call retrieve_url for each of
  495.    them. If the html is non-zero, treat the file as HTML, and
  496.    construct the URL-s accordingly.
  497.  
  498.    If recursive is set, recursive_retrieve will be called after each
  499.    file. */
  500. uerr_t
  501. retrieve_from_file(const char *file, int html, int *count)
  502. {
  503.    char *filename, *new;
  504.    int first_time, dt;
  505.    uerr_t status;
  506.    urlpos *url_list, *cur_url;
  507.  
  508.    /* If spider-mode is on, we do not want get_urls_html barfing
  509.       errors on baseless links. */
  510.    url_list = (html ? get_urls_html(file, NULL, opt.spider)
  511.            : get_urls_file(file));
  512.    status = RETROK;             /* Suppose everything is OK. */
  513.    *count = 0;                  /* Reset the URL count. */
  514.    for (first_time = 1, cur_url = url_list; cur_url;
  515.     cur_url = cur_url->next, ++*count)
  516.    {
  517.       if (opt.quota && opt.downloaded > opt.quota)
  518.       {
  519.      status = QUOTEXC;
  520.      break;
  521.       }
  522.       status = retrieve_url(cur_url->url, &filename, &new, NULL, &dt);
  523.       if (opt.recursive && status == RETROK && (dt & TEXTHTML))
  524.      status = recursive_retrieve(filename, new ? new : cur_url->url,
  525.                      first_time ? RFIRST_TIME : 0);
  526.       if (new)
  527.      free(new);
  528.       if (filename)
  529.      free(filename);
  530.       first_time = 0;
  531.    }
  532.    
  533.    /* Free the linked list of URL-s. */
  534.    free_urlpos(url_list);
  535.    
  536.    return status;
  537. }
  538.  
  539. /* Print 'giving up', or 'retrying', depending on the action to
  540.    do. Numbers represent the attempt number and the attempt limit
  541.    (please don't ask which one is which). */
  542. void
  543. printwhat(int n1, int n2)
  544. {
  545.    if (opt.verbose)
  546.    {
  547.       if (n1 == n2)
  548.      fprintf(opt.lfile, "Giving up.\n\n");
  549.       else
  550.      fprintf(opt.lfile, "Retrying.\n\n");
  551.    }
  552. }
  553.  
  554.